package cn.bonoon.kernel.support.services;

import org.springframework.transaction.annotation.Transactional;

import cn.bonoon.kernel.bytecode.EntityWriter;
import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.filters.VisibleScopeFilter;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.StandardOperator;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.searcher.StandardSearcher;
import cn.bonoon.kernel.support.services.handler.EditHandler;
import cn.bonoon.kernel.support.services.handler.EditMovableHandler;

/**
 * <pre>
 * 对一个数据库对象进行增、删、改、查比较完整的操作的定义；
 * 
 * 可以在增、删、改处理操作执行之前或之后添加相应的逻辑处理代码
 * 增：可以重写{@link AbstractService#onSave(OperateEvent, Persistable)}
 * 删：可以重写{@link AbstractService#onDelete(OperateEvent, Persistable)}
 * 改：可以重写{@link AbstractService#onUpdate(OperateEvent, Persistable)}
 * 
 * 如果是需要修改到用户操作范围的限制方式，则可以重写以下方法：
 * 删：可以重写{@link AbstractService#__delete(OperateEvent, Persistable)}
 * 改：可以重写{@link AbstractService#__update(OperateEvent, Persistable)}
 * </pre>
 * @author jackson
 *
 * @param <E>
 */
@SuppressWarnings("unchecked")
public abstract class AbstractService<E extends Persistable> extends AbstractOperateService<E> implements GenericService<E>{

	protected EditHandler editHandler;
	protected StandardOperator operator;
	
	@Override
	protected StandardSearcher build(Class<E> entityClass) {
		return operator = new StandardOperator(entityClass, applicationContext);
	}
	
	protected void initMovableHandler(EntityDescriptor entityDescriptor, Class<E> entityClass){
		editHandler = new EditMovableHandler<E>(entityDescriptor.getName());
		super.initMovableHandler(entityDescriptor, entityClass);
	}
	
	@Override
	protected final void initUnmovable(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		super.initUnmovable(entityDescriptor, entityClass);
		initUnmovableHandler(entityDescriptor, entityClass);
	}
	
	/** 初始化不可移动的情况下的实体编辑处理器 */
	protected void initUnmovableHandler(EntityDescriptor entityDescriptor, Class<E> entityClass){
		editHandler = EditHandler.standard;
	}
	
	@Override
	@Transactional
	public final E update(OperateEvent event, E entity) throws Exception{
		
		editable(event);
		
		return __update(event, entity);
	}

	@Override
	@Transactional
	public final E save(OperateEvent event, E entity) throws Exception{
		
		editable(event);
		
		return __save(event, entity);
	}

	@Override
	@Transactional
	public E save(IOperator operator, E entity) {
		
		editable(operator);
		
		return save(entity);
	}
		
	protected E save(E entity) {
		entityManager.persist(entity);
		return entity;
	}

	@Override
	@Transactional
	public E update(IOperator operator, E entity) {
		
		editable(operator);
		
		return update(entity);
	}
		
	protected E update(E entity) {
		entityManager.merge(entity);
		return entity;
	}

	@Override
	@Transactional
	public void delete(IOperator operator, E entity) {
		
		editable(operator);
		
		delete(entity);
	}
	
	protected void delete(E entity) {
		entityManager.remove(entity);
	}
	
	/**
	 * <pre>
	 * 具体执行保存的方法，执行的前需要检查用户的操作权限，再调用相应的处理器来处理（如：树、文件等）
	 * 子类可以重写该方法来实现其他更为复杂的业务处理逻辑
	 * 
	 * 该方法包括了对用户操作范围限制的过滤器：{@link VisibleScopeFilter}
	 * 如果只需要在对象提交到数据库的前或后追加事件的，可以重写{@link #onUpdate(OperateEvent, Persistable)}方法
	 * </pre>
	 */
	protected E __update(OperateEvent event, E entity) throws Exception{
		scopeFilter.check(event, entity);
		if(onUpdate(event, entity)){
			return entity;
		}
		throw new RuntimeException("更新实体失败！" + entity);
	}
	
	/**
	 * <pre>
	 * 重写该方法可以简单在的对象被提交到数据库之前或之后添加处理逻辑；
	 * 
	 * 如果需要改变用户操作范围的限制的，需要重写{@link #__update(OperateEvent, Persistable)}方法
	 * </pre>
	 */
	protected boolean onUpdate(OperateEvent event, E entity) throws Exception{
		return editHandler.updateHandler(entityManager, event, entity);
	}

	/**
	 * <pre>
	 * 具体执行保存的方法，执行的前需要检查用户的操作权限，再调用相应的处理器来处理（如：树、文件等）
	 * 子类可以重写该方法来实现其他更为复杂的业务处理逻辑
	 * 
	 * 这个方法没法在提交到数据库完成之后进行一些逻辑处理，可以重写{@link #onSave(OperateEvent, Persistable)}方法
	 * </pre>
	 */
	protected E __save(OperateEvent event, E entity) throws Exception{
		if(onSave(event, entity)){
			return entity;
		}
		throw new RuntimeException("添加实体失败！" + entity);
	}
	
	/** 可以在对象被提交到数据库之前或之后进行一些逻辑的处理； */
	protected boolean onSave(OperateEvent event, E entity) throws Exception{
		return editHandler.insertHandler(entityManager, event, entity);
	}
	
	/** 子类可以通过重写该访问来改变普通对象与数据库实体对象自动相互转值的行为 */
	protected E onConvert(OperateEvent event) throws Throwable{
		Object data = event.getSource();
		EntityWriter setter =  operator.getEntityWriter(data.getClass());
		return (E)setter.writeInsert(data, event, entityManager);
	}

	/** 子类可以通过重写该访问来改变普通对象与数据库实体对象自动相互转值的行为 */
	protected E __convert(OperateEvent event, E entity, Object data) throws Exception{
		EntityWriter setter =  operator.getEntityWriter(data.getClass());
		return (E)setter.writeUpdate(data, event, entityManager, entity);
	}
	
	protected E __update(OperateEvent event, E entity, Object data) throws Exception{
		E result = __convert(event, entity, data);
		return __update(event, result);
	}
	
	@Override
	@Transactional
	public final E update(OperateEvent event, Long id) {
		
		editable(event);
		
		try{
			Long eid = event.decryptId(id);
			return __update(event, __get(eid), event.getSource());
		}catch(Throwable t){
			throw new RuntimeException(t);
		}
	}

	@Override
	@Transactional
	public final E save(OperateEvent event) {
		
		editable(event);
		
		try{
			return __save(event, onConvert(event));
		}catch(Throwable t){
			throw new RuntimeException(t);
		}
	}
	
	@Override
	@Transactional
	public final void delete(OperateEvent event, E entity) {
		
		editable(event);
		
		__delete(event, entity);
	}
	
	/**
	 * <pre>
	 * 删除指定的对象
	 * 
	 * 子类可以重写该方法，该方法包含了对用户操作范围的判断
	 * </pre>
	 * @param event
	 * @param entity
	 */
	protected void __delete(OperateEvent event, E entity){
		scopeFilter.check(event, entity);
		onDelete(event, entity);
	}
	
	/**
	 * <pre>
	 * 如果只需要在删除前或删除之后进行一些逻辑处理的，可以重写该方法
	 * </pre>
	 * @param event
	 * @param entity
	 */
	protected void onDelete(OperateEvent event, E entity){
		deleteHandler.handler(entityManager, event, entity);
	}
}
